import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
// interface ThreeType {
//   boxRef //画布容器节点
//   canvas //画布节点
//   camera: THREE.Camera | null //场景
//   renderer: THREE.WebGLRenderer | null //渲染器
//   objectLoader // obj加载器
//   scene: THREE.Scene | null //场景
//   controls //轨道控制器
//   meshList: Array<any> //记录场景模型 用于退出时销毁模型
//   frameId //渲染函数id
// }
// interface HelperTypes {
//   stats //性能插件
//   grid
//   axesHelper
// }
export const useThreeHooks = () => {
  const threeInfo = {
    boxRef: null,
    canvas: null,
    camera: null,
    scene: null,
    controls: null,
    meshList: [],
    frameId: null,
  };

  const helperTypes = {
    stats: null, //性能插件
    grid: null, //性能插件
    axesHelper: null, //性能插件
  };
  // 创建边框帮助器
  function createBoundingHelper(object, color = 0xffffff) {
    const helper = new THREE.BoxHelper(object, color); // 创建边框帮助器
    helper.material.depthTest = true; // 避免边框帮助器被遮挡
    helper.material.transparent = true; // 使边框帮助器半透明
    return helper;
  }
  // 添加实体
  function addEntity(entity) {
    threeInfo.scene?.add(entity);
    threeInfo.meshList.push(entity);
  }
  // 渲染函数
  const render = fn => {
    if (helperTypes.stats) helperTypes.stats?.update();
    if (fn) {
      fn();
    }
    threeInfo.frameId = requestAnimationFrame(() => {
      render(fn);
    });
    threeInfo.controls.update();
    threeInfo.renderer?.render(threeInfo.scene, threeInfo.camera);
  };
  // 初始化场景
  function initScance(boxRef, canvas) {
    threeInfo.boxRef = boxRef;
    threeInfo.canvas = canvas;
    threeInfo.scene = new THREE.Scene();
    return Promise.resolve(true);
  }
  //初始化相机
  function initCamera(fov = 75, aspect = 1 / 2, near = 0.1, far = 1000) {
    if (threeInfo.canvas) {
      if (aspect === 1 / 2) {
        aspect = threeInfo.canvas.clientWidth / threeInfo.canvas.clientHeight;
      }
      threeInfo.camera = new THREE.PerspectiveCamera(
        fov, //视野范围
        aspect, //（宽高比）画布尺寸【照片的大小】
        near, //离开相机的距离【近端】
        far, //离开相机的距离【远端】
      );
      return Promise.resolve(threeInfo.camera);
    }
    return Promise.reject();
  }
  // 添加灯光
  function addLight(light, lightHelper) {
    threeInfo.scene?.add(light);
    threeInfo.meshList.push(light);
    if (lightHelper) {
      threeInfo.scene?.add(lightHelper);
      threeInfo.meshList.push(lightHelper);
    }
  }
  // 网格辅助线GridHelper
  /**
   *
   * @param size -- 网格宽度，默认为 10.
   * @param divisions -- 等分数，默认为 10.
   * @param colorCenterLine -- 中心线颜色，默认 0x444444
   * @param colorGrid --  网格线颜色，默认为 0x888888
   * @returns
   */
  function initGridHelper(
    size = 10,
    divisions = 10,
    colorCenterLine = 0x444444,
    colorGrid = 0x888888,
  ) {
    helperTypes.grid = new THREE.GridHelper(
      size,
      divisions,
      colorCenterLine,
      colorGrid,
    );
    helperTypes.grid.material.opacity = 0.8; //透明度
    helperTypes.grid.material.transparent = true;
    helperTypes.grid.name = 'helper';
    threeInfo.scene?.add(helperTypes.grid);
    threeInfo.meshList.push(helperTypes.grid);
  }

  // 三维坐标轴 x,y,z
  /**
   *
   * @param size  -- 尺寸
   */
  function initAxesHelper(size = 20) {
    helperTypes.axesHelper = new THREE.AxesHelper(size);
    threeInfo.scene?.add(helperTypes.axesHelper);
    threeInfo.meshList.push(helperTypes.axesHelper);
  }
  // 性能监视器【记得渲染函数中update】
  function initStats() {
    if (threeInfo.canvas) {
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      helperTypes.stats = new Stats();
      helperTypes.stats.setMode(0);
      helperTypes.stats.domElement.style.position = 'absolute';
      helperTypes.stats.domElement.style.left = '0px';
      helperTypes.stats.domElement.style.top = '0px';
      const box = threeInfo.boxRef;
      box.appendChild(helperTypes.stats.domElement);
    }
  }
  // 渲染器
  /**
   *
   * @param color  渲染背景色
   */
  function initRender(color = 0x050505) {
    if (threeInfo.canvas) {
      threeInfo.renderer = new THREE.WebGL1Renderer({
        canvas: threeInfo.canvas,
        antialias: true,
        alpha: true,
      });
      threeInfo.renderer.setSize(
        threeInfo.canvas.clientWidth,
        threeInfo.canvas.clientHeight,
      );
      threeInfo.renderer.setClearColor(color); // 渲染背景色
      threeInfo.renderer.setPixelRatio(window.devicePixelRatio); //屏幕像素比
    }
  }
  // 轨道控制器
  function initControls() {
    if (threeInfo.camera) {
      threeInfo.controls = new OrbitControls(
        threeInfo.camera,
        threeInfo.renderer?.domElement,
      );
      // threeInfo.controls.enableDamping = true
      // threeInfo.controls.autoRotate = false //设置自动旋转
      // threeInfo.controls.autoRotateSpeed = 5 //设置自动速递
      // threeInfo.controls.enableZoom = true // 是否可以缩放
      // threeInfo.controls.enablePan = true //是否平移
      return Promise.resolve(threeInfo.controls);
    }
    return Promise.reject();
  }

  /**
   * 清除模型，模型中有 group 和 scene,需要进行判断
   * @param scene
   * @returns
   */
  function clearScene() {
    // 释放监听事件
    if (listeners.length > 0) {
      listeners.forEach(element => {
        removeEventListener(element, onMouseStart);
      });
    }

    // 从scene中删除模型并释放内存
    if (threeInfo.meshList.length > 0) {
      for (let i = 0; i < threeInfo.meshList.length; i++) {
        const currObj = threeInfo.meshList[i];

        // 判断类型
        if (currObj instanceof THREE.Scene) {
          const children = currObj.children;
          for (let i = 0; i < children.length; i++) {
            deleteGroup(children[i]);
          }
        } else {
          deleteGroup(currObj);
        }
        threeInfo.scene?.remove(currObj);
      }
    }
    try {
      threeInfo.scene?.clear();
      threeInfo.renderer?.dispose();
      threeInfo.renderer?.forceContextLoss();
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      threeInfo.renderer.content = null;
      cancelAnimationFrame(threeInfo.frameId);
      // THREE.PLATFORM.dispose()
      console.log(threeInfo.renderer?.info);
      // const gl = threeInfo.renderer.domElement.getContext('webgl')
      // gl && gl.getExtension('WEBGL_lose_context').loseContext()
    } catch (e) {
      console.log(e);
    }
  }
  // 删除group，释放内存 【未完善】
  function deleteGroup(group) {
    //console.log(group);
    if (!group) return;
    // 删除掉所有的模型组内的mesh
    group.traverse(function(item) {
      if (item instanceof THREE.Mesh) {
        item.geometry.dispose(); // 删除几何体
        item.material.dispose(); // 删除材质
        item.material.map?.dispose();
        item.material.envMap?.dispose();
      } else if (item instanceof THREE.Sprite) {
        item.geometry.dispose(); // 删除几何体
        item.material.dispose(); // 删除材质
        item.material.map?.dispose();
      } else {
        console.log(item);
        // item.geometry.dispose() // 删除几何体
        // item.material.map?.dispose()
      }
    });
  }
  /**
   * 创建OBJ模型
   * @param objUrl OBJ位置
   * @param loaderUrl 纹理位置
   * @returns
   */
  function buildObjEntity(objUrl, loaderUrl) {
    return new Promise((resolve, reject) => {
      if (!threeInfo.objectLoader) {
        threeInfo.objectLoader = new OBJLoader();
      }
      threeInfo.objectLoader.load(objUrl, obj => {
        const textureLoader = new THREE.TextureLoader();
        obj?.traverse(child => {
          if (child instanceof THREE.Mesh) {
            //设置模型纹理
            const texture = textureLoader.load(loaderUrl);
            child.material.map = texture;
          }
        });
        resolve(obj);
      });
    });
  }
  // ========== 同上 【 创建OBJ模型】
  function buildAsyncObjEntity(objUrl, loaderUrl) {
    // eslint-disable-next-line no-async-promise-executor
    return new Promise(async (resolve, reject) => {
      if (!threeInfo.objectLoader) {
        threeInfo.objectLoader = new OBJLoader();
      }
      const obj = await threeInfo.objectLoader.loadAsync(objUrl);
      obj?.traverse(async child => {
        if (child instanceof THREE.Mesh) {
          //设置模型纹理
          const textureLoader = new THREE.TextureLoader();
          const texture = await textureLoader.loadAsync(loaderUrl);
          child.material.map = texture;
          resolve(obj);
        }
      });
    });
  }
  /**
   * 背景透明png贴图
   * @param imgUrl 图片路径
   * @param width
   * @param height
   * @param widthSegments
   * @param heightSegments
   * @returns
   */
  async function buildPlaneEntity(
    imgUrl,
    width,
    height,
    widthSegments,
    heightSegments,
  ) {
    const geometry = new THREE.PlaneGeometry(
      width,
      height,
      widthSegments,
      heightSegments,
    );
    const textureLoader = new THREE.TextureLoader();
    const texture = await textureLoader.loadAsync(imgUrl);
    const material = new THREE.MeshBasicMaterial({
      map: texture,
      transparent: true,
      opacity: 1.0,
      side: THREE.DoubleSide,
      depthWrite: false,
    });
    const mesh = new THREE.Mesh(geometry, material);
    return mesh;
  }

  // 点击模型
  let startTime = ''; // 触摸开始时间
  let endTime = ''; // 触摸结束时间
  let moveTime = ''; // 触摸时间
  function onMouseStart(event) {
    startTime = new Date().getTime();
  }
  // 结束点击
  function onMouseUp(event, callback) {
    endTime = new Date().getTime();
    moveTime = endTime - startTime;
    if (threeInfo.canvas && moveTime < 300 && threeInfo.camera) {
      // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
      const mouseX = (event.offsetX / threeInfo.canvas.clientWidth) * 2 - 1;
      const mouseY = -(event.offsetY / threeInfo.canvas.clientHeight) * 2 + 1;
      const vector = new THREE.Vector3(mouseX, mouseY, 0.5).unproject(
        threeInfo.camera,
      );
      const raycaster = new THREE.Raycaster(
        threeInfo.camera.position,
        vector.sub(threeInfo.camera.position).normalize(),
      );
      raycaster.setFromCamera(
        new THREE.Vector2(mouseX, mouseY),
        threeInfo.camera,
      );
      if (threeInfo.scene) {
        const intersects = raycaster.intersectObjects(threeInfo.scene.children);
        if (intersects.length > 0) {
          callback(intersects);
        } else {
          callback([]);
        }
      }
    }
  }
  // const listeners = [] as Array<{
  //   key
  //   fun
  // }>
  const listeners = [];
  /**
   * 射线拾取模型
   * @param intersectList 带参函数(Array<any>) 回调参数为射线接触到的模型列表
   */
  function initRaycaster(intersectList) {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    threeInfo.canvas?.addEventListener('mousedown', onMouseStart),
      listeners.push({
        key: 'mousedown',
        fun: onMouseStart,
      });
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    threeInfo.canvas?.addEventListener('mouseup', event => {
      onMouseUp(event, back => {
        intersectList(back);
      });
    });
    listeners.push({
      key: 'mouseup',
      fun: onMouseUp,
    });
  }

  // 获取模型位置信息
  function getModelScreenPosition(model, camera = threeInfo.camera) {
    const worldPosition = new THREE.Vector3();
    model.getWorldPosition(worldPosition);
    const screenPosition = worldPosition.project(camera);
    const devicePosition = new THREE.Vector3();
    devicePosition.x =
      ((screenPosition.x + 1) / 2) * threeInfo.canvas.clientWidth;
    devicePosition.y =
      ((-screenPosition.y + 1) / 2) * threeInfo.canvas.clientHeight;
    devicePosition.z = screenPosition.z;
    return devicePosition;
  }
  return {
    threeInfo,
    helperTypes,
    addEntity, //添加实体
    render, // 渲染函数
    initScance, // 初始化场景
    initCamera, //初始化相机
    addLight, //添加灯光
    initGridHelper, //网格辅助线
    initAxesHelper, //三维坐标轴辅助
    initStats, //性能监视器
    initRender, //渲染器
    initControls, //轨道控制器
    clearScene, //清除模型
    buildObjEntity, //创建OBJ模型
    buildAsyncObjEntity, //创建OBJ异步模型
    buildPlaneEntity, //背景透明png贴图
    initRaycaster, //射线拾取模型
    createBoundingHelper, //创建边框帮助器
    getModelScreenPosition, //
  };
};
